package com.cfam.holidays.utils;

import com.cfam.holidays.config.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 目前从2019年支持到2024年
 */
@Slf4j
@Component
public class HolidaysUtil {

    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    private static final int DATE_SPLIT_LENGTH = 2;

    public void setHolidayList(List<String> holidayList) {
        this.holidayList = holidayList;
    }

    private static List<String> holidayList;

    public void setChangedWorkDayList(List<String> changedWorkDayList) {
        this.changedWorkDayList = changedWorkDayList;
    }

    private static List<String> changedWorkDayList;

    @PostConstruct
    public void init(){
        initHolidayData();
    }

    public void initHolidayData(){
        log.info("初始化法定节假日");
        try {
            InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("法定节假日.xlsx");
            Workbook workbook = new XSSFWorkbook(resourceAsStream);
            Sheet sheet = workbook.getSheetAt(0);
            List<String> holidayList = new ArrayList<>();
            List<String> changedWorkDayList = new ArrayList<>();
            for (int j = 1; j <= sheet.getLastRowNum(); j++) {
                Row row = sheet.getRow(j);
                if (row != null) {
                    if(row.getCell(2)!=null) {
                        CellType cellType = row.getCell(2).getCellType();
                        String holiday = "";
                        if(cellType == CellType.NUMERIC){
                            //获取数字类型的单元格中的数据NUMERIC
                            double numericCellValue = row.getCell(2).getNumericCellValue();
                            //stripTrailingZeros()：去除末尾多余的0，toPlainString()：输出时不用科学计数法
                            String s = new BigDecimal(String.valueOf(numericCellValue)).stripTrailingZeros().toPlainString();
                            holiday = s;
                        }else if(cellType == CellType.STRING){
                            String s = row.getCell(2).getStringCellValue();
                            holiday = s;
                        }
                        Date date = parse2Date(holiday);
                        LocalDate holidayDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                        holidayList.add(formatter.format(holidayDate));
                    }
                    if(row.getCell(3)!=null) {
                        CellType cellType = row.getCell(3).getCellType();
                        String changedWorkDay = "";
                        if(cellType == CellType.NUMERIC){
                            double numericCellValue = row.getCell(2).getNumericCellValue();
                            String s = new BigDecimal(String.valueOf(numericCellValue)).stripTrailingZeros().toPlainString();
                            changedWorkDay = s;
                        }else if(cellType == CellType.STRING){
                            String s = row.getCell(2).getStringCellValue();
                            changedWorkDay = s;
                        }
                        Date date = parse2Date(changedWorkDay);
                        LocalDate changedWorkDayDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                        changedWorkDayList.add(formatter.format(changedWorkDayDate));
                    }
                }
            }
            setHolidayList(holidayList);
            setChangedWorkDayList(changedWorkDayList);
        } catch (Exception e) {
            log.error("初始化法定节假日报错！", e);
        }
    }

    public static Date parse2Date(String str) throws Exception {
        str = str.trim();
        String pattern = "\\d{4}([^\\d]?)\\d{1,2}\\1\\d{1,2}( \\d{1,2}([^\\d])\\d{1,2})?";
        // 创建 Pattern 对象
        Pattern r = Pattern.compile(pattern);
        // 现在创建 matcher 对象
        Matcher m = r.matcher(str);
        String dateSplit, timeSplit;
        if (m.find()) {
            dateSplit = m.group(1);
            timeSplit = m.group(3);
            String formatStr = String.format("yyyy%sMM%sdd", dateSplit, dateSplit);
            if (timeSplit != null) {
                String timeStr = str.substring(str.indexOf(" "));
                String[] split = timeStr.split(timeSplit);
                if (split.length == DATE_SPLIT_LENGTH) {
                    formatStr += String.format(" HH%smm", timeSplit);
                }
                if (split.length > DATE_SPLIT_LENGTH) {
                    formatStr += String.format(" HH%smm%sss", timeSplit, timeSplit);
                }
            }
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(formatStr);
            return simpleDateFormat.parse(str);
        } else {
            throw new Exception("输入的时间格式不符");
        }
    }

    /**
     * 是否是法定工作日
     * @param date 日期
     * @return
     */
    public static boolean isWorkDay(Date date) {
        try {
            LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            String dateString = formatter.format(localDate);
            if(holidayList.contains(dateString)){
                return false;
            }
            if(changedWorkDayList.contains(dateString)){
                return true;
            }
            switch (localDate.getDayOfWeek()){
                case SUNDAY: return false;
                case SATURDAY: return false;
                default: return true;
            }
        } catch (Exception e) {
            log.error("判定法定工作日失败:{}", e.getMessage(), e);
            throw new BaseException("判定法定工作日失败:{}", e.getMessage());
        }
    }


}
